package cn.lingyangwl.framework.mybatis.mate.fieldunique;

import cn.lingyangwl.framework.mybatis.mate.annotations.FieldUniqueCheck;
import cn.lingyangwl.framework.mybatis.mate.inter.EntityFieldUniqueCheck;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

/**
 * 字段唯一校验处理
 *
 * @author shenguangyang
 */
@Aspect
public class FieldUniqueCheckAspect {
    private static final Logger log = LoggerFactory.getLogger(FieldUniqueCheckAspect.class);

    // 配置织入点
    @Pointcut("@annotation(cn.lingyangwl.framework.mybatis.mate.annotations.FieldUniqueCheck)")
    public void fieldUniqueCheckPointCut() {
    }

    @Around(value = "fieldUniqueCheckPointCut()")
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        return handleFieldUniqueCheck(pjp);
    }

    protected Object handleFieldUniqueCheck(ProceedingJoinPoint pjp) throws Throwable {
        // 获得注解
        FieldUniqueCheck fieldUniqueCheck = getAnnotationLog(pjp);
        if (fieldUniqueCheck == null) {
            return pjp.proceed();
        }
        Object[] args = pjp.getArgs();
        if (args != null && args.length == 1) {
            Object object = args[0];
            // 判断参数是否是BaseEntityMark类型
            // 一个参数
            if (object instanceof EntityFieldUniqueCheck) {
                CheckInfoBefore checkInfoBefore = FieldUniqueCore.checkBefore(object, fieldUniqueCheck.type());
                if (checkInfoBefore == null) {
                    return pjp.proceed();
                }
                String cacheKey = checkInfoBefore.getCacheKey();
                IFieldUniqueCheckLock fieldUniqueCheckLock = FieldUniqueCore.getFieldUniqueCheckLock();
                if (fieldUniqueCheckLock != null) {
                    if (!fieldUniqueCheckLock.lock(cacheKey)) {
                        throw new BizException("当前数据正在被操作, 请稍后再试");
                    }
                    try {
                        FieldUniqueCore.doCheck(checkInfoBefore);
                        return pjp.proceed();
                    } finally {
                        fieldUniqueCheckLock.unlock(cacheKey);
                    }
                } else {
                    synchronized (cacheKey.intern()) {
                        FieldUniqueCore.doCheck(checkInfoBefore);
                        return pjp.proceed();
                    }
                }
            }
        }
        return pjp.proceed();
    }


    /**
     * 是否存在注解，如果存在就获取
     */
    private FieldUniqueCheck getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(FieldUniqueCheck.class);
        }
        return null;
    }
}
